﻿using MvvmFoundation.Wpf;
using ServiceOperater.Helpers;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Xml;

namespace ServiceOperater.ViewModels
{

    // 例子: D:\Projects\KanqDesktopProjects\QueryZJK\ViewModels\MainViewModel.cs
    public sealed class MainViewModel : ObservableObject
    {
        private static FileSystemWatcher watcher = new FileSystemWatcher();

        public MainViewModel()
        {
            FileCollection = new ObservableCollection<FileTreeNodeViewModel>();

            // 加载默认目录下所有的service文件, 形成目录树形结构
            initServiceDataSource();

            // 开始实时监控
            monitorPath();

            instantiateCommand();


        }

        // http://blog.csdn.net/chen_zw/article/details/7916262
        private void monitorPath()
        {
            //  Path ：设置要监视的目录的路径。
            watcher.Path = ConfigHelper.ServiceFolderPath;
            //  IncludeSubdirectories ：设置是否级联监视指定路径中的子目录。
            watcher.IncludeSubdirectories = true;
            //  Filter ：设置筛选字符串，用于确定在目录中监视哪些类型的文件。
            //watcher.Filter = "*.xml";
            // NotifyFilter ：设置文件的哪些属性的变动会触发Changed事件，同时监控多个属性变动可以按“或”组合。
            //                 （默认值为 NotifyFilter.LastWrite | NotifyFilter.FileName | NotifyFilter.DirectoryName 组合）
            watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName;

            //------------- event
            watcher.Created += (sender, args) =>
            {
                // object sender, FileSystemEventArgs e
                //    文件增删改时被调用的处理方法  

                initServiceDataSource();
            };

            watcher.Deleted += (sender, args) =>
            {
                initServiceDataSource();
            };
            watcher.Changed += (sender, args) =>
            {
                initServiceDataSource();
            };
            //重命名事件与增删改传递的参数不一样。  
            watcher.Renamed += (sender, args) =>
            {
                // object sender,RenamedEventArgs e)
                //    文件重命名时被调用的处理方法
                initServiceDataSource();
            };

            // ----------------- begin monitor

            watcher.EnableRaisingEvents = true;  //启动监控  
        }

        private void initServiceDataSource()
        {
            var list = new List<string>();

            string dirPath = ConfigHelper.ServiceFolderPath;//文件夹起始的路径
            if (!Directory.Exists(dirPath))
            {
                string errorInfo = String.Format("[ {0} ] do not exist!", dirPath);
                App.Messenger.NotifyColleagues(MessengerToken.DIALOG_SHOW, errorInfo);
                return;
            }

            DispatcherHelper.CheckBeginInvokeOnUI(() =>
            {
                FileCollection.Clear();
                var directory = new DirectoryInfo(dirPath);
                constructTree(directory, FileCollection);
            });
        }

        public static void constructTree(DirectoryInfo di, ObservableCollection<FileTreeNodeViewModel> collection)
        {
            FileInfo[] fileInfoColleciton = di.GetFiles("*.xml");//指定类型
            foreach (FileInfo fileInfo in fileInfoColleciton)
            {
                collection.Add(constructTreeNode(fileInfo, null));
            }

            DirectoryInfo[] dirInfoColleciton = di.GetDirectories();//指定类型
            foreach (DirectoryInfo dirInfo in dirInfoColleciton)
            {
                var tnvm = constructTreeNode(dirInfo, null);
                collection.Add(tnvm);
                constructTree(dirInfo, tnvm.Children);
            }
        }

        private static FileTreeNodeViewModel constructTreeNode(FileSystemInfo fileInfo, FileTreeNodeViewModel parent)
        {

            //string filename = name.Substring(0, fullname.LastIndexOf("."));//去掉后缀名。
            var tnvm = new FileTreeNodeViewModel(fileInfo.Name, fileInfo.FullName, parent);
            return tnvm;
        }

        private void instantiateCommand()
        {
            OnFileTreeNodeSelectionChangedCommand = new RelayCommand<FileTreeNodeViewModel>((selectedFtnvm) =>
            {
                loadServiceXmlFile(selectedFtnvm);

            }, (selectedFtnvm) =>
            {
                if (selectedFtnvm == null)
                {
                    return false;
                }
                // 目录点击无效
                return (!selectedFtnvm.IsDirectory);
            });

            OnSearchFileTxtChangedCommand = new RelayCommand<String>((searchTxt) =>
            {
                iterFile(FileCollection, searchTxt, (fileVM, sTxt) =>
                {
                    if (String.IsNullOrWhiteSpace(sTxt))
                    {

                        fileVM.IsHighight = false;
                        return;
                    }
                    fileVM.IsHighight = (fileVM.Text.ToLowerInvariant().Contains(sTxt.ToLowerInvariant()));
                });
            }, (searchTxt) =>
            {
                return true;
            });

            // FileTreeNodeViewModel
            OpenParentFolderCommand = new RelayCommand<FileTreeNodeViewModel>((selectedFtnvm) =>
            {
                FileHelper.ExploreFile(selectedFtnvm.FullPath);
                //var parentDir = Directory.GetParent(selectedFtnvm.FullPath);
                //System.Diagnostics.Process.Start("explorer.exe ", parentDir.FullName);
            }, (selectedFtnvm) =>
            {
                return true;
            });

            CopyFilePathCommand = new RelayCommand<FileTreeNodeViewModel>((selectedFtnvm) =>
            {
                var fileFullPath = selectedFtnvm.FullPath;
                // http://www.cnblogs.com/zhaotianff/p/5841942.html
                // 第二个参数设置为false，或者不设置，将在程序运行结束后不保留剪切板内容。
                Clipboard.SetDataObject(fileFullPath, true);
            }, (selectedFtnvm) =>
            {
                return true;
            });

            //F2,右键菜单
            ModifyFileNameCommand = new RelayCommand<FileTreeNodeViewModel>((selectedFtnvm) =>
            {
                selectedFtnvm.IsInEditMode = true;
            }, (selectedFtnvm) =>
            {
                return true;
            });

            // Enter
            SaveFileNameCommand = new RelayCommand<FileTreeNodeViewModel>((selectedFtnvm) =>
            {
                // 这个会触发FileTreeNodeViewModel的SaveFileNameCommand, 因为其绑定在了LostFocus事件上
                selectedFtnvm.IsInEditMode = false;
            }, (selectedFtnvm) =>
            {
                return true;
            });

            //Cancel
            CancelEditFileNameCommand = new RelayCommand<FileTreeNodeViewModel>((selectedFtnvm) =>
            {
                App.Messenger.NotifyColleagues(MessengerToken.TRANSACTION_ROLLBACK, selectedFtnvm);
                selectedFtnvm.IsInEditMode = false;
            }, (selectedFtnvm) =>
            {
                return true;
            });

            // 新建文件夹
            AddFolderCommand = new RelayCommand<FileTreeNodeViewModel>((selectedFtnvm) =>
            {
                ServiceFileOperater.CreateEmptyFolder(selectedFtnvm);
            }, (selectedFtnvm) =>
            {
                return true;
            });
            // 新建文件
            AddFileCommand = new RelayCommand<FileTreeNodeViewModel>((selectedFtnvm) =>
            {
                ServiceFileOperater.CreateEmptyFile(selectedFtnvm);
            }, (selectedFtnvm) =>
            {
                return true;
            });

            DelFileCommand = new RelayCommand<FileTreeNodeViewModel>((selectedFtnvm) =>
            {
                if (FileHelper.isDir(selectedFtnvm.FullPath))
                {
                    Directory.Delete(selectedFtnvm.FullPath, true);
                }
                else
                {
                    File.Delete(selectedFtnvm.FullPath);
                }
            }, (selectedFtnvm) =>
            {
                return true;
            });

            RefreshFileTreeCommand = new RelayCommand<Object>((selectedFtnvm) =>
            {
                initServiceDataSource();
            }, (selectedFtnvm) =>
            {
                return true;
            });

            RefreshServiceTreeCommand = new RelayCommand<FileTreeNodeViewModel>((selectedFtnvm) =>
            {
                loadServiceXmlFile(selectedFtnvm);
            }, (selectedFtnvm) =>
            {
                return (selectedFtnvm != null && FileHelper.isNotDir(selectedFtnvm.FullPath));
            });

            AnalysisCommand = new RelayCommand<Object>((obj) =>
            {
                initServiceDataSource();

                App.Messenger.NotifyColleagues(MessengerToken.WINDOW_SHOW, new AnalysisResultViewModel());

            }, (obj) =>
            {
                return true;
            });

            ConfigCommand = new RelayCommand<Object>((obj) =>
            {
                //App.Messenger.NotifyColleagues(MessengerToken.WINDOW_SHOW, new ConfigViewModel());
                App.Messenger.NotifyColleagues(MessengerToken.DIALOG_SHOW, "Config");
            }, (obj) =>
            {
                return true;
            });
        }

        /// <summary>
        ///  递归
        /// </summary>
        /// <param name="list">所操作的集合</param>
        /// <param name="searchTxt">所要查找的字符</param>
        /// <param name="action">集合中的每个Item所要进行的操作</param>
        private void iterFile(ObservableCollection<FileTreeNodeViewModel> list, String searchTxt, Action<FileTreeNodeViewModel, String> action)
        {
            foreach (var fileVM in list)
            {
                action(fileVM, searchTxt);

                if (fileVM.Children.Count > 0)
                {
                    iterFile(fileVM.Children, searchTxt, action);
                }
            }
        }

        public static void loadServiceXmlFile(FileTreeNodeViewModel selectedFtnvm)
        {
            if (selectedFtnvm.IsDirectory)
            {
                return;
            }

            // http://www.cnblogs.com/hnsongbiao/p/5636076.html
            var xmlFilePath = selectedFtnvm.FullPath;

            selectedFtnvm.ServiceCollection.Clear();

            XmlDocument doc = new XmlDocument();
            doc.Load(xmlFilePath);
            XmlElement root = doc.DocumentElement;

            XmlNodeList serviceNodeList = root.SelectNodes("/service-config/service");
            foreach (XmlNode serviceNode in serviceNodeList)
            {
                var serviceId = serviceNode.Attributes["id"].InnerText;
                var sTnvm = new ServiceTreeNodeViewModel(serviceId, selectedFtnvm);
                selectedFtnvm.ServiceCollection.Add(sTnvm);

                foreach (XmlNode actionNode in serviceNode.SelectNodes("action"))
                {
                    var aTnvm = constructActionTreeNodeViewModel(actionNode, sTnvm);
                    sTnvm.ActionChildren.Add(aTnvm);
                }
            }
        }

        private static ActionTreeNodeViewModel constructActionTreeNodeViewModel(XmlNode actionNode, ServiceTreeNodeViewModel parent)
        {
            var actionNameAttribute = actionNode.Attributes["name"];
            var actionName = actionNameAttribute == null ? " " : actionNameAttribute.InnerText;
            var aTnvm = new ActionTreeNodeViewModel(actionName, parent);

            var propertyNodes = actionNode.SelectNodes("property");
            foreach (XmlNode propertyNode in propertyNodes)
            {
                var propName = propertyNode.Attributes["name"].InnerText;
                var propValue = propertyNode.Attributes["value"].InnerText;

                //            

                // 最好还是用这个, 有通知功能嘛
                //PropertyInfo pInfo = aTnvm.GetType().GetProperty(propName, BindingFlags.Public | BindingFlags.Instance);
                //Type pType = pInfo.PropertyType;
                //pInfo.SetValue(aTnvm, Convert.ChangeType(propValue, pType), null);

                FieldInfo fInfo = aTnvm.GetType().GetField(propName, BindingFlags.NonPublic | BindingFlags.Instance);
                if (null != fInfo)
                {
                    Type fType = fInfo.FieldType;
                    fType = Nullable.GetUnderlyingType(fType) ?? fType;
                    fInfo.SetValue(aTnvm, propValue == null ? null : Convert.ChangeType(propValue, fType));
                }



            }

            return aTnvm;
        }



        #region Props
        // 必须如此, 但是为啥.
        private ObservableCollection<FileTreeNodeViewModel> fileCollection;
        public ObservableCollection<FileTreeNodeViewModel> FileCollection
        {
            get
            {
                return fileCollection;
            }
            set
            {
                if (fileCollection == value)
                {
                    return;
                }

                fileCollection = value;

                RaisePropertyChanged("FileCollection");
            }
        }

        #endregion

        #region Commands

        public RelayCommand<FileTreeNodeViewModel> OnFileTreeNodeSelectionChangedCommand { get; private set; }

        public RelayCommand<String> OnSearchFileTxtChangedCommand { get; private set; }

        public RelayCommand<FileTreeNodeViewModel> OpenParentFolderCommand { get; private set; }

        public RelayCommand<FileTreeNodeViewModel> CopyFilePathCommand { get; private set; }

        // F2, 右键菜单
        public RelayCommand<FileTreeNodeViewModel> ModifyFileNameCommand { get; private set; }

        //Enter
        public RelayCommand<FileTreeNodeViewModel> SaveFileNameCommand { get; private set; }

        //Cancel
        public RelayCommand<FileTreeNodeViewModel> CancelEditFileNameCommand { get; private set; }

        public RelayCommand<FileTreeNodeViewModel> AddFolderCommand { get; private set; }

        public RelayCommand<FileTreeNodeViewModel> AddFileCommand { get; private set; }

        public RelayCommand<FileTreeNodeViewModel> DelFileCommand { get; private set; }

        public RelayCommand<Object> RefreshFileTreeCommand { get; private set; }

        public RelayCommand<FileTreeNodeViewModel> RefreshServiceTreeCommand { get; private set; }

        public RelayCommand<Object> AnalysisCommand { get; private set; }

        public RelayCommand<Object> ConfigCommand { get; private set; }
        #endregion

        #region 枚举数据源
        //public IEnumerable<ValueDescription> QXDMList
        //{ get { return EnumHelper.GetAllValuesAndDescriptions<QXDM>(); } }

        //public IEnumerable<ValueDescription> DJLXList
        //{ get { return EnumHelper.GetAllValuesAndDescriptions<DJLX>(); } }
        #endregion
    }
}
